﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;

namespace Narwhunderful.Aphelia.Framework
{

    public abstract class UpdatableComponentCollection<T> : DesignableComponent, IComponentCollection<T>, IDisposable where T : IUpdatableComponent
    {

        IComparer<T> _updatableComponentComparer = new UpdatableComponentComparer<T>();
        protected virtual IComparer<T> UpdatableComponentComparer
        {
            get
            {
                return _updatableComponentComparer;
            }
            set
            {
                _updatableComponentComparer = value;
            }
        }

        List<T> _updatableComponents = new List<T>();
        public virtual List<T> UpdatableComponents
        {
            get
            {
                return _updatableComponents;
            }
        }

        #region IDesignableComponent

        protected internal override void OnDesigningChanged()
        {
            if (base.IsDesigning)
            {
                for (int x = 0; x < _updatableComponents.Count; x++)
                {
                    T component = _updatableComponents[x];
                    if (component is IDesignableComponent)
                    {
                        IDesignableComponent designableComponent = (IDesignableComponent)component;
                        if (!designableComponent.IsDesigning) designableComponent.BeginDesigning();
                    }
                }
            }
            else
            {
                Sort();
                for (int x = 0; x < _updatableComponents.Count; x++)
                {
                    T component = _updatableComponents[x];
                    if (component is IDesignableComponent)
                    {
                        IDesignableComponent designableComponent = (IDesignableComponent)component;
                        if (designableComponent.IsDesigning) designableComponent.EndDesigning();
                    }
                }
            }
            base.OnDesigningChanged();
        }

        #endregion

        #region IComponentCollection

        public event EventHandler<ComponentEventArgs<T>> AddingComponent;
        public event EventHandler<ComponentEventArgs<T>> ComponentAdded;
        public event EventHandler<ComponentEventArgs<T>> RemovingComponent;
        public event EventHandler<ComponentEventArgs<T>> ComponentRemoved;
        public event EventHandler<EventArgs> Sorting;

        bool _needsToSort = false;
        protected virtual bool NeedsToSort
        {
            get
            {
                return _needsToSort;
            }
            set
            {
                _needsToSort = value;
            }
        }

        public virtual void Add(T component, bool sortComponents)
        {
            OnAddingComponent(new ComponentEventArgs<T>(component));
            _updatableComponents.Add(component);
            OnComponentAdded(new ComponentEventArgs<T>(component));
            if (sortComponents) _needsToSort = true;
        }

        public void Add(T component)
        {
            this.Add(component, true);
        }

        public virtual void Remove(T component, bool sortComponents)
        {
            OnRemovingComponent(new ComponentEventArgs<T>(component));
            _updatableComponents.Remove(component);
            OnComponentRemoved(new ComponentEventArgs<T>(component));
            if (sortComponents) _needsToSort = true;
        }

        public void Remove(T component)
        {
            this.Remove(component, true);
        }

        public virtual void Sort()
        {
            if (_updatableComponentComparer != null) _updatableComponents.Sort(_updatableComponentComparer);
            OnSorting();
            _needsToSort = false;
        }

        protected internal virtual void OnAddingComponent(ComponentEventArgs<T> e)
        {
            AddingComponent.SafeInvoke(this, e);
        }

        protected internal virtual void OnComponentAdded(ComponentEventArgs<T> e)
        {
            ComponentAdded.SafeInvoke(this, e);
        }

        protected internal virtual void OnRemovingComponent(ComponentEventArgs<T> e)
        {
            RemovingComponent.SafeInvoke(this, e);
        }

        protected internal virtual void OnComponentRemoved(ComponentEventArgs<T> e)
        {
            ComponentRemoved.SafeInvoke(this, e);
        }

        protected internal virtual void OnSorting()
        {
            Sorting.SafeInvoke(this, new EventArgs());
        }

        #endregion

        #region IDisposable

        protected override void Dispose(bool disposing)
        {
            if (disposing) _updatableComponents.Clear();
        }

        #endregion

        public virtual void Update(GameTime gameTime)
        {
            if (_needsToSort) Sort();
            for (int x = 0; x <= _updatableComponents.Count - 1; x++) _updatableComponents[x].Update(gameTime);
        }

    }

}
